#include "stdafx.h"
#include "IndexBuffer.h"

#include "Log.h"
#include "Exception.h"
#include "MemUtils.h"
#include "ErrorHandlers.h"

namespace Cvekas {

IndexBuffer::IndexBuffer(ResourceId id, D3DDevicePtr device, const std::string& name, 
	bool sixteen_bits, uint indice_count, bool is_dynamic)
	: 
GpuBuffer(id, device, name, is_dynamic), 
sixteen_bits(sixteen_bits), 
indice_count(indice_count)
{
	usage = is_dynamic ? D3DUSAGE_DYNAMIC : 0;
	size_in_bytes = sixteen_bits ? indice_count * 2 : indice_count * 4;
	create();
}

IndexBuffer::~IndexBuffer()
{
	if(!is_released)
	{
		safeRelease(index_buffer);
		LOG(FORMAT("Index buffer %s released", % name));
	}
}

bool IndexBuffer::isLocked() const
{
	return is_locked;
}

LockedBuffer IndexBuffer::lock(bool read_only)
{
	if(is_locked)
		throw EXCEPTION("Index buffer is already locked!");

	is_locked = true;

	void* data;
	DWORD usage;

	if(is_dynamic)
		usage = D3DLOCK_DISCARD;
	else
		usage = read_only ? D3DLOCK_READONLY : 0;

	E_E(index_buffer->Lock(0, 0, &data, usage));

	LockedBuffer result;
	result.data = data;
	result.size = size_in_bytes;

	return result;
}

void IndexBuffer::unlock()
{
	if(!is_locked)
		throw EXCEPTION("Index buffer is not locked!");

	E_E(index_buffer->Unlock());
	is_locked = false;
}

int IndexBuffer::getIndexCount() const
{
	return indice_count;
}

bool IndexBuffer::isSixteenBits() const
{
	return sixteen_bits;
}

IDirect3DIndexBuffer9* IndexBuffer::getD3DIndexBuffer() const
{
	if(is_ready)
		return index_buffer;
	else
		throw EXCEPTION("Index buffer is not ready for usage");
}

void IndexBuffer::create()
{
	LOG(FORMAT("Creating index buffer %s", % name));

	D3DFORMAT format = sixteen_bits ? D3DFMT_INDEX16 : D3DFMT_INDEX32;
	D3DPOOL pool = is_dynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
	
	E_E(device->CreateIndexBuffer(size_in_bytes, usage, format, pool, &index_buffer, NULL));
	
	is_ready = true;
	is_locked = false;
}

void IndexBuffer::onDeviceLost()
{
	// Only dynamic buffers must be released on device lost
	if(is_dynamic)
	{
		LOG(FORMAT("Releasing dynamic index buffer %s", % name));
		safeRelease(index_buffer);
		is_released = true;
	}

	is_ready = false;
}

void IndexBuffer::onDeviceReset()
{
	if(is_dynamic && is_released)
		create();

	is_ready = true;
}

} // namespace